﻿<?php
/**
 * 数据库类
 */
class db extends obj
{
    private static $instance = array();
    
    protected $connection = null; // 数据库连接
    protected $cursor = null; // 查询结果游标

    
    /**
     * 构造函数 私有， 单件模式, 防止用户创建实例
     * 
     * @param string $host 数据库主机名
     * @param string $user 用户名
     * @param string $pass 密码
     * @param string $name 数据库名
     * 
     */
    private function __construct($host, $user, $pass, $name)
    {
        if (!function_exists('mysql_connect'))
        {
            $this->set_error('MySql函数不可用');
            return false;
        }
        
        if (!($this->connection = mysql_connect($host, $user, $pass, true)))
        {
            $this->set_error('连接 MySQL 失败');
            return false;
        }
        
        if (!mysql_select_db($name, $this->connection))
        {
            $this->set_error('数据库 ' . $name . ' 不存在');
            return false;
        }
        
        mysql_query("SET NAMES 'utf8'", $this->connection);
    }

    /**
     * 析构函数
     */
    public function __destruct()
    {
        self::$instance = null;
        if (is_resource($this->connection))
        {
            mysql_close($this->connection);
        }
    }

    /**
     * 防止克隆
     */
    private function __clone()
    {
    }

    /**
     * 获取数据库实例
     * 
     * @param string $host 数据库主机名
     * @param string $user 用户名
     * @param string $pass 密码
     * @param string $name 数据库名
     * 
     * @return object
     * 
     */
    public static function &get_instance($host, $user, $pass, $name)
    {
        $db = $host . ',' . $user . ',' . $pass . ',' . $name;
        if (!array_key_exists($db, self::$instance))
        {
            self::$instance[$db] = new db($host, $user, $pass, $name);
        }
        return self::$instance[$db];
    }

    /**
     * 执行 sql 语句
     * 
     * @param string $sql 查询语句
     * @param int $offset 读取记录偏移
     * @param int $limit 取多少条记录
     * 
     * @return bool
     * 
     */
    public function execute($sql, $offset = 0, $limit = 0)
    {
        if (!is_resource($this->connection))
        {
            return false;
        }
        
        if ($offset > 0 || $limit > 0)
        {
            $sql .= ' LIMIT ' . $offset . ', ' . $limit;
        }
        
        $this->cursor = mysql_query($sql, $this->connection);
        
        if (!$this->cursor)
        {
            $this->set_error(mysql_error($this->connection) . ' SQL=' . $sql);
            return false;
        }
        return $this->cursor;
    }

    /**
     * 返回单一查询结果, 多行多列记录时, 只返回第一行第一列
     * 
     * @param string $sql 查询语句
     * 
     * @return string
     * 
     */
    public function get_result($sql)
    {
        if (!($cursor = $this->execute($sql, 0, 1)))
        {
            return null;
        }
        $data = null;
        $row = mysql_fetch_row($cursor);
        if ($row !== false) $data = $row[0];
        mysql_free_result($cursor);
        return $data;
    }

    /**
     * 返回查询单列结果的数组。$index:  取第几列
     * 
     * @param string $sql 查询语句
     * @param int $index 第几列
     * @param string $key 返回结果索引列
     * 
     * @return array
     * 
     */
    public function get_results($sql, $index = 0, $key = null)
    {
        if (!($cursor = $this->execute($sql)))
        {
            return null;
        }
        
        $datas = array();
        $row = mysql_fetch_row($cursor);
        while ($row !== false)
        {
            if ($key !== null)
            {
                $datas[$row->$key] = $row[$index];
            }
            else
            {
                $datas[] = $row[$index];
            }
            $row = mysql_fetch_row($cursor);
        }
        mysql_free_result($cursor);
        return $datas;
    }

    /**
     * 返回一个数据库记录对象
     * 
     * @param string $sql 查询语句
     * 
     * @return object
     * 
     */
    public function get_obj($sql)
    {
        if (!($cursor = $this->execute($sql, 0, 1)))
        {
            return null;
        }
        $data = null;
        $obj = mysql_fetch_object($cursor);
        if ($obj !== false) $data = $obj;
        mysql_free_result($cursor);
        return $data;
    }

    /**
     * 返回一个对象数组，如果设置了 $key, 该数组按该 key 生成索引下标。
     * 
     * @param string $sql 查询语句
     * @param int $offset 读取记录偏移
     * @param int $limit 取多少条记录
     * @param string $key 返回结果索引列
     * 
     * @return array
     * 
     */
    public function get_objs($sql, $offset = 0, $limit = 0, $key = '')
    {
        if (!($cursor = $this->execute($sql, $offset, $limit)))
        {
            return array();
        }
        $datas = array();
        $row = mysql_fetch_object($cursor);
        while ($row !== false)
        {
            if ($key)
            {
                $datas[$row->$key] = $row;
            }
            else
            {
                $datas[] = $row;
            }
            $row = mysql_fetch_object($cursor);
        }
        mysql_free_result($cursor);
        return $datas;
    }

    /**
     * 插入一个对象到数据库
     * 
     * @param string $table 表名
     * @param object $obj 要插入数据库的对象或数组，对象属性需要和该表字段一致
     * 
     * @return bool
     * 
     */
    public function insert($table, &$obj)
    {
        $fields = array();
        $values = array();
        foreach (get_object_vars($obj) as $key => $value)
        {
            if (is_array($value) || is_object($value) || $value === NULL)
            {
                continue;
            }
            
            $fields[] = '`' . $key . '`';
            $values[] = '\'' . $value . '\'';
        }
        
        $sql = 'INSERT INTO `' . $table . '` (' . implode(',', $fields) . ') VALUES (' . implode(',', $values) . ') ';
        if (!$this->execute($sql))
        {
            return false;
        }
        
        return true;
    }

    /**
     * 更新一个对象到数据库
     * 
     * @param string $table 表名
     * @param object $obj 要插入数据库的对象或数组，对象属性需要和该表字段一致
     * @param string $key_name 主键名
     * @param bool $update_null 是否更新空值字段
     * 
     * @return bool
     * 
     */
    public function update($table, &$obj, $key_name, $update_null = true)
    {
        $datas = array();
        $where = null;
        foreach (get_object_vars($obj) as $key => $value)
        {
            if (is_array($value) || is_object($value))
            {
                continue;
            }
            
            // 主键不更新
            if ($key == $key_name)
            {
                $where = '`' . $key_name . '`=\'' . $value . '\'';
                continue;
            }
            if ($value === null)
            {
                if ($update_null)
                {
                    $value = 'NULL';
                }
                else
                {
                    continue;
                }
            }
            else
            {
                $value = '\'' . $value . '\'';
            }
            $datas[] = '`' . $key . '`=' . $value;
        }
        $sql = 'UPDATE `' . $table . '` SET ' . implode(",", $datas);
        if ($where)
        {
            $sql .= ' WHERE ' . $where;
        }
        
        return $this->execute($sql);
    }

    /**
     * 获取 insert 插入后产生的 id
     * 
     * @return int
     * 
     */
    public function get_insert_id()
    {
        return mysql_insert_id($this->connection);
    }

    /**
     * 获取当前数据库所有表名
     * 
     * @return array
     * 
     */
    public function get_tables()
    {
        return $this->get_objs('SHOW TABLES');
    }

    /**
     * 获取一个表的字段列表
     * 
     * @return array
     * 
     */
    public function get_table_fields($table)
    {
        $fields = $this->get_objs('SHOW FIELDS FROM ' . $table);
        
        $datas = array();
        foreach ($fields as $field)
        {
            $datas[$field->Field] = $field;
        }
        return $datas;
    }

    /**
     * 获取 MYSQL 版本号
     * 
     * @return string
     * 
     */
    public function get_version()
    {
        return mysql_get_server_info($this->connection);
    }

}
